package com.syyo.gulimall.admin.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;


/**
 * @author Administrator
 * <p>
 * 身份证工具类
 */
public class IdCardUtil {

    /**
     * 省、直辖市代码表：
     * 11 : 北京  12 : 天津  13 : 河北       14 : 山西  15 : 内蒙古
     * 21 : 辽宁  22 : 吉林  23 : 黑龙江  31 : 上海  32 : 江苏
     * 33 : 浙江  34 : 安徽  35 : 福建       36 : 江西  37 : 山东
     * 41 : 河南  42 : 湖北  43 : 湖南       44 : 广东  45 : 广西      46 : 海南
     * 50 : 重庆  51 : 四川  52 : 贵州       53 : 云南  54 : 西藏
     * 61 : 陕西  62 : 甘肃  63 : 青海       64 : 宁夏  65 : 新疆
     * 71 : 台湾
     * 81 : 香港  82 : 澳门
     * 91 : 国外
     */
    private static final String[] cityCode = {"11", "12", "13", "14", "15", "21",
            "22", "23", "31", "32", "33", "34", "35", "36", "37", "41", "42",
            "43", "44", "45", "46", "50", "51", "52", "53", "54", "61", "62",
            "63", "64", "65", "71", "81", "82", "91"};

    /**
     * 每位加权因子
     */
    private static final int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    private static final String[] SX = {"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"};

    /**
     * 验证所有的身份证的合法性
     *
     * @param idcard 身份证
     * @return 合法返回true，否则返回false
     */
    public static boolean isValidatedAllIdcard(String idcard) {
        if (idcard == null || "".equals(idcard)) {
            return false;
        }
        if (idcard.length() == 15) {
            return validate15IDCard(idcard);
        } else if (idcard.length() == 18) {
            return validate18Idcard(idcard);
        } else {
            return false;
        }
    }

    /**
     * 判断18位身份证的合法性
     * 根据〖中华人民共和国国家标准GB11643-1999〗中有关公民身份号码的规定，公民身份号码是特征组合码，由十七位数字本体码和一位数字校验码组成。
     * 排列顺序从左至右依次为：六位数字地址码，八位数字出生日期码，三位数字顺序码和一位数字校验码。
     * 顺序码: 表示在同一地址码所标识的区域范围内，对同年、同月、同 日出生的人编定的顺序号，顺序码的奇数分配给男性，偶数分配 给女性。
     * 1.前1、2位数字表示：所在省份的代码； 2.第3、4位数字表示：所在城市的代码； 3.第5、6位数字表示：所在区县的代码；
     * 4.第7~14位数字表示：出生年、月、日； 5.第15、16位数字表示：所在地的派出所的代码；
     * 6.第17位数字表示性别：奇数表示男性，偶数表示女性；
     * 7.第18位数字是校检码：也有的说是个人信息码，一般是随计算机的随机产生，用来检验身份证的正确性。校检码可以是0~9的数字，有时也用x表示。
     * 第十八位数字(校验码)的计算方法为： 1.将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为：7 9 10 5 8 4
     * 2 1 6 3 7 9 10 5 8 4 2
     * 2.将这17位数字和系数相乘的结果相加。
     * 3.用加出来和除以11，看余数是多少
     * 4.余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3
     * 5.通过上面得知如果余数是2，就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10，身份证的最后一位号码就是2。
     */
    public static boolean validate18Idcard(String idcard) {
        if (idcard == null) {
            return false;
        }
        // 非18位为假
        int s = 18;
        if (idcard.length() != s) {
            System.out.println("身份证位数不正确!");
            return false;
        }
        // 获取前17位
        String idcard17 = idcard.substring(0, 17);
        // 前17位全部为数字
        if (!isDigital(idcard17)) {
            return false;
        }
        String provinceid = idcard.substring(0, 2);
        // 校验省份
        if (!checkProvinceid(provinceid)) {
            return false;
        }
        // 校验出生日期
        String birthday = idcard.substring(6, 14);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        try {
            Date birthDate = sdf.parse(birthday);
            String tmpDate = sdf.format(birthDate);
            // 出生年月日不正确
            if (!tmpDate.equals(birthday)) {
                return false;
            }
        } catch (ParseException e1) {
            return false;
        }
        // 获取第18位
        String idcard18Code = idcard.substring(17, 18);
        char[] c = idcard17.toCharArray();
        int[] bit = converCharToInt(c);
        int sum17 = 0;
        sum17 = getPowerSum(bit);
        // 将和值与11取模得到余数进行校验码判断
        String checkCode = getCheckCodeBySum(sum17);
        if (null == checkCode) {
            return false;
        }
        // 将身份证的第18位与算出来的校码进行匹配，不相等就为假
        if (!idcard18Code.equalsIgnoreCase(checkCode)) {
            return false;
        }
        // System.out.println("正确");
        return true;
    }

    /**
     * 校验15位身份证
     * 只校验省份和出生年月日
     */
    public static boolean validate15IDCard(String idcard) {
        if (idcard == null) {
            return false;
        }
        // 非15位为假
        int s = 15;
        if (idcard.length() != s) {
            return false;
        }
        // 15全部为数字
        if (!isDigital(idcard)) {
            return false;
        }
        String provinceid = idcard.substring(0, 2);
        // 校验省份
        if (!checkProvinceid(provinceid)) {
            return false;
        }
        String birthday = idcard.substring(6, 12);
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
        try {
            Date birthDate = sdf.parse(birthday);
            String tmpDate = sdf.format(birthDate);
            // 身份证日期错误
            if (!tmpDate.equals(birthday)) {
                return false;
            }
        } catch (ParseException e1) {
            return false;
        }
        return true;
    }

    /**
     * 将15位的身份证转成18位身份证
     */
    public static String convertIdcarBy15bit(String idcard) {
        if (idcard == null) {
            return null;
        }
        // 非15位身份证
        int s = 15;
        if (idcard.length() != s) {
            return null;
        }
        // 15全部为数字
        if (!isDigital(idcard)) {
            return null;
        }
        String provinceid = idcard.substring(0, 2);
        // 校验省份
        if (!checkProvinceid(provinceid)) {
            return null;
        }
        String birthday = idcard.substring(6, 12);
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
        Date birthdate = null;
        try {
            birthdate = sdf.parse(birthday);
            String tmpDate = sdf.format(birthdate);
            // 身份证日期错误
            if (!tmpDate.equals(birthday)) {
                return null;
            }
        } catch (ParseException e1) {
            return null;
        }
        Calendar cday = Calendar.getInstance();
        cday.setTime(birthdate);
        String year = String.valueOf(cday.get(Calendar.YEAR));
        String idcard17 = idcard.substring(0, 6) + year + idcard.substring(8);
        char c[] = idcard17.toCharArray();
        String checkCode = "";
        // 将字符数组转为整型数组
        int bit[] = converCharToInt(c);
        int sum17 = 0;
        sum17 = getPowerSum(bit);
        // 获取和值与11取模得到余数进行校验码
        checkCode = getCheckCodeBySum(sum17);
        // 获取不到校验位
        if (null == checkCode) {
            return null;
        }
        // 将前17位与第18位校验码拼接
        idcard17 += checkCode;
        return idcard17;
    }

    /**
     * 获取籍贯
     */
    public static String getNativePlace(String idCard) {
        String provinceid = idCard.substring(0, 2);
        int i = Integer.parseInt(provinceid);
        String checkCode = "";
        switch (i) {
            case 11:
                checkCode = "北京";
                break;
            case 12:
                checkCode = "天津";
                break;
            case 13:
                checkCode = "河北";
                break;
            case 14:
                checkCode = "山西";
                break;
            case 15:
                checkCode = "内蒙古";
                break;
            case 21:
                checkCode = "辽宁";
                break;
            case 22:
                checkCode = "吉林";
                break;
            case 23:
                checkCode = "黑龙江";
                break;
            case 31:
                checkCode = "上海";
                break;
            case 32:
                checkCode = "江苏";
                break;
            case 33:
                checkCode = "浙江";
                break;
            case 34:
                checkCode = "安徽";
                break;
            case 35:
                checkCode = "福建";
                break;
            case 36:
                checkCode = "江西";
                break;
            case 37:
                checkCode = "山东";
                break;
            case 41:
                checkCode = "河南";
                break;
            case 42:
                checkCode = "湖北";
                break;
            case 43:
                checkCode = "湖南";
                break;
            case 44:
                checkCode = "广东";
                break;
            case 45:
                checkCode = "广西";
                break;
            case 46:
                checkCode = "海南";
                break;
            case 50:
                checkCode = "重庆";
                break;
            case 51:
                checkCode = "四川";
                break;
            case 52:
                checkCode = "贵州";
                break;
            case 53:
                checkCode = "云南";
                break;
            case 54:
                checkCode = "西藏";
                break;
            case 61:
                checkCode = "陕西";
                break;
            case 62:
                checkCode = "甘肃";
                break;
            case 63:
                checkCode = "青海";
                break;
            case 64:
                checkCode = "宁夏";
                break;
            case 65:
                checkCode = "新疆";
                break;
            case 71:
                checkCode = "台湾";
                break;
            case 81:
                checkCode = "香港";
                break;
            case 82:
                checkCode = "澳门";
                break;
            default:
                checkCode = "国外";
        }
        return checkCode;
    }

    /**
     * 根据身份证号判断性别
     *
     * @param idNumber
     * @return
     */
    public static String getGender(String idNumber) throws IllegalArgumentException {
        if (idNumber.length() != 18 && idNumber.length() != 15) {
            throw new IllegalArgumentException("身份证号长度错误");
        }
        int gender = 0;
        if (idNumber.length() == 18) {
            //如果身份证号18位，取身份证号倒数第二位
            char c = idNumber.charAt(idNumber.length() - 2);
            gender = Integer.parseInt(String.valueOf(c));
        } else {
            //如果身份证号15位，取身份证号最后一位
            char c = idNumber.charAt(idNumber.length() - 1);
            gender = Integer.parseInt(String.valueOf(c));
        }
        if (gender % 2 == 1) {
            return "男";
        } else {
            return "女";
        }
    }

    /**
     * 根据身份证号计算年龄
     */
    public static int getPersonAgeFromIdCard(String idCard) {
        try {
            // 截取身份证中出行人出生日期中的年、月、日
            Integer personYear = Integer.parseInt(idCard.substring(6, 10));
            Integer personMonth = Integer.parseInt(idCard.substring(10, 12));
            Integer personDay = Integer.parseInt(idCard.substring(12, 14));
            Calendar cal = Calendar.getInstance();
            // 得到当前时间的年、月、日
            Integer yearNow = cal.get(Calendar.YEAR);
            Integer monthNow = cal.get(Calendar.MONTH) + 1;
            Integer dayNow = cal.get(Calendar.DATE);
            // 用当前年月日减去生日年月日
            int yearMinus = yearNow - personYear;
            int monthMinus = monthNow - personMonth;
            int dayMinus = dayNow - personDay;
            //先大致赋值
            int age = yearMinus;
            // 出生年份大于当前年份
            if (monthMinus < 0) {
                // 出生月份小于当前月份时，还没满周岁
                age = age - 1;
            }
            if (monthMinus == 0) {
                // 当前月份为出生月份时，判断日期
                if (dayMinus < 0) {
                    // 出生日期小于当前月份时，没满周岁
                    age = age - 1;
                }
            }
            return age;
        } catch (Exception e) {
            return 0;
        }
    }

    /***
     * 获取生肖
     */
    public static String getShengXiao(String idCard) {
        try {
            if (!trueIdCard(idCard)) {
                return "";
            }
            int year = Integer.parseInt(idCard.substring(6, 10));
            int x = (year - 4) % 12;
            String ret = "";
            ret = SX[x];
            return ret;
        } catch (Exception e) {
            return "";
        }

    }

    /***
     * 获取星座
     */
    public static String getXingZuo(String idCard) {
        try {
            if (!trueIdCard(idCard)) {
                return "";
            }
            int month = Integer.parseInt(idCard.substring(10, 12));
            int days = Integer.parseInt(idCard.substring(12, 14));
            String ret = "";
            if ((month == 1 && days >= 20) || (month == 2 && days <= 18)) {
                ret = "水瓶座";
            } else if ((month == 2 && days >= 19) || (month == 3 && days <= 20)) {
                ret = "双鱼座";
            } else if ((month == 3 && days >= 21) || (month == 4 && days <= 19)) {
                ret = "白羊座";
            } else if ((month == 4 && days >= 20) || (month == 5 && days <= 20)) {
                ret = "金牛座";
            } else if ((month == 5 && days >= 21) || (month == 6 && days <= 21)) {
                ret = "双子座";
            } else if ((month == 6 && days >= 22) || (month == 7 && days <= 22)) {
                ret = "巨蟹座";
            } else if ((month == 7 && days >= 23) || (month == 8 && days <= 22)) {
                ret = "狮子座";
            } else if ((month == 8 && days >= 23) || (month == 9 && days <= 22)) {
                ret = "处女座";
            } else if ((month == 9 && days >= 23) || (month == 10 && days <= 23)) {
                ret = "天秤座";
            } else if ((month == 10 && days >= 24) || (month == 11 && days <= 22)) {
                ret = "天蝎座";
            } else if ((month == 11 && days >= 23) || (month == 12 && days <= 21)) {
                ret = "射手座";
            } else if ((month == 12 && days >= 21) || (month == 1 && days <= 19)) {
                ret = "摩羯座";
            }
            return ret;
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 获取生日 2020-01-01
     */
    public static String getBirthDay(String idCard) {
        try {
            String inputYear = getBirthDayByYear(idCard);
            String inputMonth = getBirthDayByMonth(idCard);
            String inputDay = getBirthDayByDay(idCard);
            String birthDay = inputYear + "-" + inputMonth + "-" + inputDay;
            return birthDay;
        } catch (Exception e) {
            return "";
        }
    }

    private static boolean trueIdCard(String idCard) {
        return MyStringUtils.isNotEmpty(idCard) && idCard.length() == 18;
    }

    private static String getBirthDayByYear(String identifyNumber) {
        String inputYear = "";
        if (identifyNumber.length() == 18) {
            inputYear = identifyNumber.substring(6, 10);
        }
        return inputYear;
    }

    private static String getBirthDayByMonth(String birthday) {
        String inputMonth = "";
        if (birthday.length() == 18) {
            inputMonth = birthday.substring(10, 12);
        }
        return inputMonth;
    }

    private static String getBirthDayByDay(String birthday) {
        String inputDay = "";
        if (birthday.length() == 18) {
            inputDay = birthday.substring(12, 14);
        }
        return inputDay;
    }

    /**
     * 校验省份
     *
     * @return 合法返回TRUE，否则返回FALSE
     */
    private static boolean checkProvinceid(String provinceid) {
        for (String id : cityCode) {
            if (id.equals(provinceid)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 数字验证
     */
    private static boolean isDigital(String str) {
        return str.matches("^[0-9]*$");
    }

    /**
     * 将身份证的每位和对应位的加权因子相乘之后，再得到和值
     */
    private static int getPowerSum(int[] bit) {

        int sum = 0;

        if (power.length != bit.length) {
            return sum;
        }

        for (int i = 0; i < bit.length; i++) {
            for (int j = 0; j < power.length; j++) {
                if (i == j) {
                    sum = sum + bit[i] * power[j];
                }
            }
        }
        return sum;
    }

    /**
     * 将和值与11取模得到余数进行校验码判断
     */
    private static String getCheckCodeBySum(int sum17) {
        String checkCode = null;
        switch (sum17 % 11) {
            case 10:
                checkCode = "2";
                break;
            case 9:
                checkCode = "3";
                break;
            case 8:
                checkCode = "4";
                break;
            case 7:
                checkCode = "5";
                break;
            case 6:
                checkCode = "6";
                break;
            case 5:
                checkCode = "7";
                break;
            case 4:
                checkCode = "8";
                break;
            case 3:
                checkCode = "9";
                break;
            case 2:
                checkCode = "x";
                break;
            case 1:
                checkCode = "0";
                break;
            case 0:
                checkCode = "1";
                break;
            default:
        }
        return checkCode;
    }

    /**
     * 将字符数组转为整型数组
     */
    private static int[] converCharToInt(char[] c) throws NumberFormatException {
        int[] a = new int[c.length];
        int k = 0;
        for (char temp : c) {
            a[k++] = Integer.parseInt(String.valueOf(temp));
        }
        return a;
    }


    public static void main(String[] args) {

        String gender = getGender("421126198901190038");
        System.out.println(gender);
    }

}
